package yuchen.androidocr.imageUtil;

import android.graphics.Bitmap;
import android.graphics.Color;

/**
 * Created by yuchen on 5/15/16.
 */
public class sobelEdge {

    private Bitmap image;
    private int width;
    private int height;
    private int[] grayPixels;
    private int size;
    private Bitmap outImage;
    private int[] outPixels;

    //Sobel 卷积核X
    private int[][] kernelX = {
            {-1, 0, 1},
            {-2, 0, 2},
            {-1, 0, 1}
    };

    //Sobel 卷积核Y
    private int[][] kernelY = {
            {-1, -2, -1},
            {0, 0, 0},
            {1, 2, 1}
    };

    public sobelEdge(int width, int height, Bitmap bitmap) {
        this.width = width;
        this.height = height;
        this.image = bitmap;
        this.size = width * height;
        outPixels = new int[size];
        grayPixels = new int[size];
    }

    public void readImage(Bitmap bitmap) {
        int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        createGrayImage(pixels);
        //return createBitmap(this.grayPixels);
    }

    public void createGrayImage(int[] imageData) {
        int i, j, ids;
        for (j = 0; j < width * height; j++) {
            int r = Color.red(imageData[j]);
            int g = Color.green(imageData[j]);
            int b = Color.blue(imageData[j]);
            double gray = (r * 0.3 + g * 0.59 + b * 0.11);
            grayPixels[j] = (int)gray;
        }
    }
    //得到点(x,y)处的灰度值,主要是由于JS能够识别非数字的NaN,但是Java没有,所以给他一个足够大的不可能的数来弥补这一点.
    public int getGrayPoint(int x, int y) {
        int ids = y * width + x;
        if (ids < 0 || ids >= this.width * this.height) {
            return 100000;
        } else {
            return grayPixels[ids];
        }
    }


    //算子 计算 点(x,y)处的x方向梯度大小
    protected final int GradientX(int x, int y) {

        int pixelX = (
                (kernelX[0][0] * getGrayPoint(x - 1, y - 1)) +
                        (kernelX[0][1] * getGrayPoint(x, y - 1)) +
                        (kernelX[0][2] * getGrayPoint(x + 1, y - 1)) +
                        (kernelX[1][0] * getGrayPoint(x - 1, y)) +
                        (kernelX[1][1] * getGrayPoint(x, y)) +
                        (kernelX[1][2] * getGrayPoint(x + 1, y)) +
                        (kernelX[2][0] * getGrayPoint(x - 1, y + 1)) +
                        (kernelX[2][1] * getGrayPoint(x, y + 1)) +
                        (kernelX[2][2] * getGrayPoint(x + 1, y + 1))
        );

        return pixelX;

        //return getGrayPoint(x - 1, y - 1) + 2*getGrayPoint(x - 1, y) + getGrayPoint(x - 1, y + 1)
        //- getGrayPoint(x + 1, y - 1) - 2*getGrayPoint(x + 1, y) - getGrayPoint(x + 1, y + 1);
    }// 计算像素点(x,y)X方向上的梯度值
    // 算子 计算 点(x,y)处的y方向梯度大小

    protected final int GradientY(int x, int y) {

        int pixelY = (
                (kernelX[0][0] * getGrayPoint(x - 1, y - 1)) +
                        (kernelY[0][1] * getGrayPoint(x, y - 1)) +
                        (kernelY[0][2] * getGrayPoint(x + 1, y - 1)) +
                        (kernelY[1][0] * getGrayPoint(x - 1, y)) +
                        (kernelY[1][1] * getGrayPoint(x, y)) +
                        (kernelY[1][2] * getGrayPoint(x + 1, y)) +
                        (kernelY[2][0] * getGrayPoint(x - 1, y + 1)) +
                        (kernelY[2][1] * getGrayPoint(x, y + 1)) +
                        (kernelY[2][2] * getGrayPoint(x + 1, y + 1))
        );
        return pixelY;
    }

    protected float[] gradientM() {
        int[] m_pHistogram = new int[256];
        float[] mag = new float[size];
        int gx, gy;
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                gx = GradientX(x, y);
                gy = GradientY(x, y);
                //用公式 g=|gx|+|gy|计算图像每个像素点的梯度大小.原因是避免平方和开方耗费大量时间
                //mag[y * width + x] = (float) (Math.abs(gx) + Math.abs(gy));
                if (Math.abs(gy) > 10000 || Math.abs(gy) > 10000) {
                    mag[y * width + x] = 0;
                } else {
                    float mags = (float) Math.sqrt((gx * gx) + (gy * gy));
                    if (mags > 255) {
                        mag[y * width + x] = 255;
                    } else {
                        mag[y * width + x] = mags;
                    }
                }
            }
        }
        return mag;
    }

    public int[] createEdgeImage()
    {
        float[] gradient = gradientM();// 计算图像各像素点的梯度值
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                int ids = y * width + x;
                int r = (int) gradient[y * width + x];
                int g = r;
                int b = r;
                int color = Color.rgb(r, r, r);
                this.outPixels[ids] = color;
            }
        }
        //createBitmap(outPixels);
        return outPixels;
    }

    public Bitmap createBitmap(int[] grayPixels)
    {
        Bitmap sobelImage = Bitmap.createBitmap(grayPixels,0,width,width,height,Bitmap.Config.RGB_565);
        return sobelImage;
    }
}
